Skip to content

feat(format): enumerate tracked files via git ls-files in --scope=all#1155

Open
gregmagolan wants to merge 1 commit into
mainfrom
feat/format-scope-all-git-ls-files
Open

feat(format): enumerate tracked files via git ls-files in --scope=all#1155
gregmagolan wants to merge 1 commit into
mainfrom
feat/format-scope-all-git-ls-files

Conversation

@gregmagolan

@gregmagolan gregmagolan commented May 28, 2026

Copy link
Copy Markdown
Member

Adds --scope=git to enumerate all non-gitignored tracked files via git ls-files before invoking the formatter, instead of having the formatter self-discover. --scope=all (formatter self-discovery) is unchanged.

What --scope=git does:

  • Runs git ls-files --cached --others --exclude-standard --full-name from the git root, scoped to the invoking directory when run from a subdirectory
  • Applies .gitattributes filtering (rules-lint-ignored, linguist-generated, gitlab-generated — same attributes as rules_lint)
  • Excludes files that are tracked in the index but missing from disk
  • Applies --include-pattern / --exclude-pattern against repo-relative paths before invoking the formatter (patterns are now effective in scope=all-equivalent mode)
  • Passes the resulting file list to the formatter in batches (≤128 000 chars each, matching rules_lint's format.sh cap)
  • Falls back to formatter self-discovery with a warning when git is unavailable

Why: Bare formatter binaries (e.g. @buildifier_prebuilt//buildifier) in --scope=all mode walk the filesystem and may visit gitignored generated files. --scope=git restricts the run to files git knows about. Raw formatters that only handle specific file types should pair --scope=git with --include-pattern (e.g. --include-pattern='**/*.bzl' for buildifier).

Implementation notes:

  • New helpers: _chunk_files, _filter_git_attributes, _git_ls_files, _apply_pattern_filters (extracted from duplicate pattern-filter blocks in scope=changed and the new scope=git branch)
  • _git_capture_root runs git from the git root; uses -c core.quotePath=false so non-ASCII filenames are never C-quoted in output
  • _git_capture/_git_capture_root both delegate to _git_capture_in to avoid duplicating the process-builder chain
  • lib/format_results.axl: fixed template that hardcoded --scope=changed in the "no files to format" message; now uses the actual scope value

Changes are visible to end-users: yes

  • Searched for relevant documentation and updated as needed: no
  • Breaking change (forces users to change their own code or config): no
  • Suggested release notes appear below: yes

Suggested release notes:

  • New --scope=git for aspect format: enumerates all non-gitignored files via git ls-files (respecting .gitignore and .gitattributes) before invoking the formatter. Makes --include-pattern / --exclude-pattern effective in this mode. Bare formatters like buildifier should pair --scope=git --include-pattern='**/*.bzl' --include-pattern='**/BUILD*' to scope to their supported file types.

Test plan

  • Manual testing:
    1. aspect format --scope=git in a repo with gitignored generated BUILD files — they should not be formatted
    2. aspect format --scope=git --include-pattern='**/*.bzl' — only .bzl files formatted
    3. Mark a file linguist-generated in .gitattributes — should be excluded from --scope=git
    4. aspect format --scope=all — unchanged self-discovery behavior
    5. aspect format --scope=git outside a git repo — warning emitted, formatter falls back to self-discovery

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f6b113636

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread crates/aspect-cli/src/builtins/aspect/format.axl Outdated
Comment thread crates/aspect-cli/src/builtins/aspect/format.axl Outdated
@gregmagolan gregmagolan force-pushed the feat/format-scope-all-git-ls-files branch from 659fb9c to ecb46fe Compare May 28, 2026 18:48
@aspect-workflows

aspect-workflows Bot commented May 28, 2026

Copy link
Copy Markdown

✨ Aspect Workflows Tasks

📅 Sun Jun 28 06:40:33 UTC 2026

❌ 3 failed tasks

  • ❌ format-gha-debug [format] · ⏱ 1m 18s · 🐙 GitHub Actions · ☑️ Check
    💬 failed in diff · Format failed (2 files need format)
  • ❌ format-format-repeat-task [format] · ⏱ 1m 49s · 🐙 GitHub Actions · ☑️ Check
    💬 failed in diff · Format failed (2 files need format)
  • ❌ format-gha [format] · ⏱ 1m 11s · 🐙 GitHub Actions · ☑️ Check
    💬 failed in diff · Format failed (2 files need format)

⚠️ 2 flagged tasks

  • ⚠️ delivery-gha-debug [delivery] · ⏱ 27.3s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Delivery complete (1 delivered · 2 warn · 3 skipped)
  • ⚠️ delivery-gha [delivery] · ⏱ 40s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Delivery complete (1 delivered · 2 warn · 3 skipped)

✅ 22 successful tasks

  • ✅ axl-smoke-gha-bootstrap [build] · ⏱ 20.5s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (1 built)
  • ✅ run-axl-smoke [run] · ⏱ 17.8s · 🐙 GitHub Actions · ☑️ Check
    💬 Ran //examples/deliverable:py_deliverable
  • ✅ run-axl-smoke-2 [run] · ⏱ 12.1s · 🐙 GitHub Actions · ☑️ Check
    💬 Ran //examples/deliverable:sh_deliverable
  • ✅ axl-tests-gha-bootstrap [build] · ⏱ 18.4s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (1 built)
  • ✅ build-gha-debug [build] · ⏱ 1m 16s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (166 built)
  • ✅ build-gha [build] · ⏱ 1m 9s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (166 built)
  • ✅ build-gha-ephemeral [build] · ⏱ 1m 8s · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (9 built)
  • ✅ buildifier-gha-debug [buildifier] · ⏱ 38.1s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ buildifier-gha [buildifier] · ⏱ 39.1s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ buildifier-gha-all [buildifier] · ⏱ 8.7s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ buildifier-gha-tracked [buildifier] · ⏱ 1m 18s · 🐙 GitHub Actions · ☑️ Check
    💬 Format complete (clean)
  • ✅ gazelle-gha-debug [gazelle] · ⏱ 45.1s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ gazelle-from-source-gha-debug [gazelle] · ⏱ 1m 59s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ gazelle-from-source-gha [gazelle] · ⏱ 2m 1s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ gazelle-gha [gazelle] · ⏱ 18.8s · 🐙 GitHub Actions · ☑️ Check
    💬 Gazelle complete (clean)
  • ✅ init-shell [build] · ⏱ 36.7s · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel build complete (10 built)
  • ✅ lint-gha-debug [lint] · ⏱ 1m 33s · 🐙 GitHub Actions · ☑️ Check
    💬 Lint complete (clean)
  • ✅ lint-gha [lint] · ⏱ 1m 16s · 🐙 GitHub Actions · ☑️ Check
    💬 Lint complete (clean)
  • ✅ test-gha-debug [test] · ⏱ 1m 20s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (26/26 passed · 26 cached)
  • ✅ test-gha-coverage [test] · ⏱ 15.4s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (1/1 passed · 1 cached)
  • ✅ test-gha-target-pattern-file [test] · ⏱ 15.4s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (1/1 passed · 1 cached)
  • ✅ test-gha [test] · ⏱ 1m 8s · ✨ Aspect · 🐙 GitHub Actions · ☑️ Check
    💬 Bazel test complete (26/26 passed · 25 cached)

🛠️ Fix

❌ format (format-gha-debug · format-format-repeat-task · format-gha)

aspect format --severity=info -- .buildkite/pipeline.yaml .circleci/config.yml

Install aspect: aspect.build/docs/cli/install

🔁 Reproduce

⚠️ delivery (delivery-gha-debug · delivery-gha)

# --mode=always --track-state=false for off-runner with no state backend.
aspect delivery \
  --commit-sha=6a07eef21dbfa47f32b21b5ed16eae45225d36f4 \
  --mode=always \
  --track-state=false \
  --dry-run=true

❌ format (format-gha-debug · format-format-repeat-task · format-gha)

aspect format --severity=fail --base-ref=origin/main

Install aspect: aspect.build/docs/cli/install


⏱ Last updated Sun Jun 28 06:43:14 UTC 2026 · 📊 GitHub API quota 3,191/15,000 (21% used, resets in 25m)
🚀 Powered by Aspect CLI (v0.0.0-dev)  |  Aspect Build · X · LinkedIn · YouTube

@gregmagolan gregmagolan force-pushed the feat/format-scope-all-git-ls-files branch 3 times, most recently from 8bd55f5 to 7f92d0b Compare May 30, 2026 04:48
@gregmagolan gregmagolan force-pushed the feat/format-scope-all-git-ls-files branch 4 times, most recently from 2ca5698 to aa1e1a0 Compare June 28, 2026 02:57
Introduces a new `--scope=tracked` value that enumerates non-gitignored
tracked files via `git ls-files` before passing them to the formatter,
preventing bare formatter binaries like buildifier from visiting gitignored
generated files.

**Scope values** (narrowest → broadest):
- `changed` (default) — files changed vs. merge base
- `tracked` — all git-tracked + untracked-but-not-ignored files via
  `git ls-files --cached --others --exclude-standard --full-name`
- `all` — formatter self-discovers files (original behavior unchanged)

**`.gitattributes` filtering** (mirrors rules_lint's `format.sh`):
Files with any of these attributes set to `"true"` or `"set"` are excluded:
- `aspect-format-ignored` — aspect-native escape hatch
- `rules-lint-ignored` — rules_lint compatibility
- `linguist-generated` — GitHub Linguist generated-file marker
- `gitlab-generated` — GitLab equivalent

**Implementation details:**
- `_git_ls_files`: returns repo-relative paths (`--full-name`) so
  `--include-pattern` / `--exclude-pattern` (documented as repo-relative)
  match correctly; scoped to CWD when invoked from a subdirectory
- `_normalize_files_for_formatter`: converts repo-relative paths to
  CWD-relative before spawning the formatter
- `_chunk_files`: splits file lists at 128 000-char batches (same cap as
  rules_lint's `format.sh`) to stay under OS arg limits; chunked loop
  replaces the single `r.spawn()` call for `scope=tracked`
- `_git_capture_root`: runs git from the repo root with
  `core.quotePath=false` so non-ASCII filenames are never C-quoted
- `_apply_pattern_filters`: extracted helper shared by `scope=changed`
  and `scope=tracked` branches
- `format_results.axl`: fixed hardcoded `--scope=changed` in the
  `no_files_to_format` template message; now uses `{{ scope }}`

**Tests:**
- `format_results_test.axl`: added scenarios 17 (`scope=tracked` with
  files) and 18 (`scope=tracked` no-files, exercises the template fix);
  loop invariant asserts `--scope=<value>` appears in no-files messages
- All CI platforms (Buildkite, CircleCI, GitLab, GitHub Actions) now
  run `--scope=tracked` and `--scope=all` in parallel with the default
  `--scope=changed` runs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gregmagolan gregmagolan force-pushed the feat/format-scope-all-git-ls-files branch from aa1e1a0 to 6a07eef Compare June 28, 2026 06:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants